;;;
;;; JaCoLiB
;;; Copyright (C) 2008 Alessandro Serra
;;; 
;;; This program is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation, either version 3 of the License, or
;;; (at your option) any later version.
;;; 
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;; 
;;; You should have received a copy of the GNU General Public License
;;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
;;;

;;;; Created on 2008-07-22 10:20:08

(in-package :jacolib)

;
; RPC Response
;

(defstruct rpc-response 
  result
  err)

; constructors 

(defun make-rpc-response-of-result (result)
  (make-rpc-response :result result :err nil))

(defun make-rpc-response-of-error (typename message)
  (declare (type string typename)
           (type string message))
  (make-rpc-response :result nil :err (list typename message)))

; json serialization
 
(def-json-serializer 'rpc-response "rpc.response" 
  (aadd "result" (rpc-response-result obj))
  (aadd "err" (rpc-response-err obj)))

(def-json-deserializer "rpc.response" 
  (let* ((v1 (afind "result" t))
         (v2 (afind "err" t)))
    (if (or (null v2) (and (listp v2) (= 2 (length v2))))
        (setf obj (make-rpc-response :result v1 :err v2))
        (error 'protocol-error :message "Deserialization error of rpc.response."))))

; utility functions

(defun rpc-response-get (res)
  (declare (type rpc-response res))
  (if (null (rpc-response-err res))
      (rpc-response-result res)
      (let ((etype (first  (rpc-response-err res)))
            (msg (second (rpc-response-err res))))
        (cond 
          ((string-equal etype "target") 
           (error 'target-error :message msg))
          ((string-equal etype "parser")
           (error 'parser-error :message msg))
          ((string-equal etype "eval") 
           (error 'eval-error :message msg))))))

(defmacro rpc-response-making (code)
  (let ((res (gensym)))
    `(let ((,res
            (handler-case
             (make-rpc-response-of-result ,code)
             (target-error(x) 
               (make-rpc-response-of-error "target"  (jacolib-error-message x)))
             (parser-error(x) 
               (make-rpc-response-of-error "parser"  (jacolib-error-message x)))
             (eval-error(x) 
               (make-rpc-response-of-error "eval" (jacolib-error-message x))))))
       ,res)))
